#pragma once
#include "NEventPublisher.h"

namespace Engine
{
template <class T> 
class NEvent : public NEventPublisher
{
	typedef std::list<NEventSubscriber*> SubscriberList;

	RTTI_DECLARATIONS(NEvent<T>, NEventPublisher)

public:
	NEvent();

	NEvent(const T message, bool deleteAfterPublish);

	virtual ~NEvent();
	
	static void Subscribe(NEventSubscriber* EventSub);

	static void Unsubcribe(NEventSubscriber* EventSub);

	static void UnsubcribeAll();

	T& GetEventMessage();
	
	void Deliver() const;

	void SetTime(const double & currentTime,const double & delay = 0.0);
	
	double GetTimeEnqueued() const;
	
	double GetDelay() const;

private:
	static SubscriberList m_subscribers;
	T m_myMessage;							//!< this events message
};

template<class T> 
RTTI_DEFINITIONS(NEvent<T>)

template<class T>
std::list<NEventSubscriber*> NEvent<T>::m_subscribers;

template<class T>
NEvent<T>::NEvent()
	:NEventPublisher()
{
}

template<class T>
NEvent<T>::NEvent(const T message, bool deleteAfterPublish)
	:NEventPublisher(m_subscribers,deleteAfterPublish),
	 m_myMessage(message)
{
}

template<class T>
NEvent<T>::~NEvent()
{
}

template<class T>
void NEvent<T>::Subscribe(NEventSubscriber * EventSub)
{
	NEvent::m_subscribers.push_front(EventSub);
}

template<class T>
void NEvent<T>::Unsubcribe(NEventSubscriber* EventSub)
{
	NEvent::m_subscribers.remove(EventSub);
}

template<class T>
void NEvent<T>::UnsubcribeAll()
{
	NEvent::m_subscribers.clear()
}

template<class T>
T& NEvent<T>::GetEventMessage()
{
	return m_myMessage;
}

template<class T>
void NEvent<T>::Deliver() const
{
	SubscriberList::iterator searcher = m_subscribers.begin();
	for(;searcher != m_subscribers.end();searcher++)
	{
		NEvent<T> * self = const_cast<NEvent<T> *>(this);
		(*searcher)->Notify(reinterpret_cast<NEventPublisher*>(self));
	}
}

template<class T>
void NEvent<T>::SetTime(const double & currentTime,const double & delay = 0.0)
{
	m_eventTime = currentTime;
	m_delay = delay;
}

template<class T>
double NEvent<T>::GetTimeEnqueued() const 
{
	return m_eventTime;
}

template<class T>
double NEvent<T>::GetDelay() const 
{
	return m_delay;
}
}